package org.raphaello.core;


import java.util.Collection;
import java.util.HashMap;


import android.util.Log;

import org.raphaello.core.Property;

public class Primitive {
	
	private static final String TAG = "Primitive";
	
	protected String mId;
	
	/** The mapping between the name of property and the property. */
	private HashMap<String, Property> mProperties;
	
	/** The children of this primitive */
	private HashMap<String, Primitive> mChildren;
	
	public Primitive(String id){
		mId = id;
		mProperties = new HashMap<String, Property>();
		mChildren = new HashMap<String, Primitive>();
	}
	
	public final void addChild(Primitive child){
		mChildren.put(child.getId(), child);
	}
	
	public final boolean containChild(String childId){
		return mChildren.containsKey(childId);
	}
	
	public final Primitive getChild(String childId){
		return mChildren.get(childId);
	}
	
	public final Collection<Primitive> getChildren(){
		return mChildren.values();
	}
	
	public final void printChildren(){
		for(Primitive child : mChildren.values()){
			Log.i(TAG, this.getClass().getName() + "(" + mId + ") has " + child.getId());
		}
	}
	
	/** A helper method for adding a new property to this */
	protected final void declareProperty(String name, String type){
		declareProperty(name, type, null);
	}
	
	
	protected final void declareProperty(String name, String type, String defaultValue){
		if(mProperties.containsKey(name)){
			Log.e(TAG, "Can not add the property because " + name + " is not existed");
		}
		else{
			mProperties.put(name, new Property(name, type, defaultValue));
			Log.d(TAG, "Declaring property (" + name + ", " + type + ")");
		}
	}
	
	/** A helper method for filling the existing property */
	public final void fillProperty(String name, String value){
		Primitive owner = getPropertyOwner(name);
		if(owner != null){
			// Assume that the owner has the target property
			Property property = owner.mProperties.get(name);
			property.fillValue(value);
			
			Log.d(TAG, "Filling property (" + name + ", " + value + ")");
		}
		else{
			Log.e(TAG, "Can not fill the property because " + name + " is not existed");
		}
	}
	
	/** A check function the named property exists or not */
	public final boolean containProperty(String name) {
		Primitive owner = getPropertyOwner(name);
		
		if(owner != null)
			return true;
		else
			return false;
	}
	
	
	private Primitive getPropertyOwner(String name) {
		// TODO : Improve this function not to check for every time.
		
		Primitive owner;
		if(mProperties.containsKey(name)){
			return this;
		}
		else{
			for(Primitive child : mChildren.values()){
				owner = child.getPropertyOwner(name); 
				if(owner != null){
					return owner;
				}
			}
			return null;
		}
	}
	
	public final String getId(){
		return mId;
	}
	
	
	public final Object getProperty(String name){
		Property property = getPropertyOwner(name).mProperties.get(name);
		if(property == null){
			Log.e(TAG, "The property named " + name + " is not existed.");
			return null;
		}
		else{
			return property.getValue();
		}
		
	}
	
	/** Check that all of properties defined is filled or not */
	public final boolean isValid(){
		
		// Check for this primitive
		for(Property property : mProperties.values()){
			if(property.isFilled() == false){
				return false;
			}
		}
		
		// Check for its children
		for(Primitive child : mChildren.values()){
			if(child.isValid() == false)
				return false;
		}
		
		return true;
	}
	
	public final void printProperties(){
		for(Property property : mProperties.values()){
			Log.i(TAG, "Name: " + property.getName() + 
					   " Type: " + property.getType() +
					   " Value: " + property.getValue());
			
		}
	}
}
